import axios from 'axios'
import type {
  AxiosInstance,
  AxiosResponse,
  RawAxiosRequestHeaders,
} from 'axios'
import { ElMessage } from 'element-plus'
// Nprogress——页面加载的虚假进度条
import NProgress from 'nprogress'
import type {
  AjaxResult,
  AxiosRequestConfigExtendType,
} from '@/types'
// import Cookies from 'js-cookie';
import { UserInfoEnum } from '@/enum'
import { useUserStoreHook } from '@/store/modules/userStore'
// import { useLoadingBar } from '@/hooks/modules/loadingBar';

// 右上角螺旋加载提示显示与否
NProgress.configure({ showSpinner: false })

// const progress = useLoadingBar();
function withRequestPage(
  config: AxiosRequestConfigExtendType,
) {
  // !目前只考虑hash模式路由
  config.requestPage = window.location.hash.slice(1)
}

let showMessage = true
export function toggleShowMessage(show: boolean) {
  showMessage = show
}

// 基础配置，url和超时时间
const baseConfig: Partial<AxiosRequestConfigExtendType> = {
  timeout: 60000,
  switchPageNotCancelRequest: false,
  withCredentials: false,
}
// 使用axios.create创建axios实例
const instance: AxiosInstance = axios.create(baseConfig)
// const contentTypeForm = 'application/x-www-form-urlencoded;charset=UTF-8';

function download(blob: Blob, fileName: string) {
  const dom = document.createElement('a')
  const url = window.URL.createObjectURL(blob)
  dom.href = url
  dom.download = decodeURI(fileName)
  dom.style.display = 'none'
  document.body.appendChild(dom)
  dom.click()
  dom.parentNode?.removeChild(dom)
  window.URL.revokeObjectURL(url)
}

/**
 * 请求拦截
 */
instance.interceptors.request.use(
  (config) => {
    // 开启进度条
    NProgress.start()
    // progress.start();

    const { addController } = usePageAjaxStore()
    addController(config)
    // 一般会请求拦截里面加token，用于后端的验证
    // const token = Cookies.get(UserInfoEnum.TOKEN);
    const token = localStorage.getItem(UserInfoEnum.TOKEN)
    token && (config.headers!.token = token)
    // !给每个请求实例都加上发出请求的页面路径，用于缓存页面相关操作
    withRequestPage(config)

    // 服务端接口带上Cookie会引发500错误
    config.headers.Cookie = null
    return config
  },
  (err: any) => {
    // 完成进度条
    NProgress.done()
    // progress.error();
    // 请求错误，这里可以用全局提示框进行提示
    return Promise.reject(err)
  },
)

/**
 * 响应拦截
 */
instance.interceptors.response.use(
  (res: AxiosResponse) => {
    if (res.headers['content-type'] === 'application/vnd.ms-excel;charset=utf8') {
      // console.warn(res.headers['content-disposition']);
      const { data, headers } = res
      const fileName = (headers['content-disposition'] || '').replace(/\s+/, '').replace(/.*;filename=(.*)/, '$1')
      const blob = new Blob([data], { type: headers['content-type'] })
      download(blob, fileName)
      return res.data
    }
    const { data } = res

    // 未设置状态码则默认成功状态
    if (!data) {
      NProgress.done()
      // progress.finish();
      return res
    }
    // 完成进度条

    // ? 文件流直接输出
    if (data instanceof Blob) {
      NProgress.done()
      // progress.finish();
      return res
    }
    const userStore = useUserStoreHook()
    if (data.code === 200) {
      NProgress.done()
      // progress.finish();
      return res
    }

    if (data.code === 401 || data.code === 402) {
      /** 登录超时清除token和用户信息 */
      // Cookies.remove(UserInfoEnum.TOKEN);
      // userStore.setUserInfo({});
      userStore.logout()
    }

    NProgress.done()
    // progress.error();

    // 系统如果有自定义code也可以在这里处理

    showMessage
    && ElMessage.warning({
      message: data.message,
    })
    return Promise.reject(data.message)
  },
  (err: any) => {
    NProgress.done()
    // progress.error();
    // !在请求失败的情况下，当前页面取消缓存
    const { abort } = withStoreOut(useKeepPageStore)()
    if (err?.code === 'ERR_CANCELED')
      abort(err.config)

    // 这里用来处理http常见错误，进行全局提示
    let msg = ''
    switch (err.response.status) {
      case 400:
        msg = '请求错误(400)'
        break
      case 401:
        msg = '未授权，请重新登录(401)'
        // 这里可以做清空storage并跳转到登录页的操作
        break
      case 403:
        msg = '拒绝访问(403)'
        break
      case 404:
        msg = '请求出错(404)'
        break
      case 408:
        msg = '请求超时(408)'
        break
      case 500:
        msg = '服务器错误(500)'
        break
      case 501:
        msg = '服务未实现(501)'
        break
      case 502:
        msg = '网络错误(502)'
        break
      case 503:
        msg = '服务不可用(503)'
        break
      case 504:
        msg = '网络超时(504)'
        break
      case 505:
        msg = 'HTTP版本不受支持(505)'
        break
      default:
        msg = `连接出错(${err.response.status})!`
        break
    }
    // 这里错误消息可以使用全局弹框展示出来
    // 比如element plus 可以使用 ElMessage
    ElMessage.error({
      showClose: true,
      message: `${msg}，请检查网络或联系管理员！`,
    })
    // 这里是AxiosError类型，所以一般我们只reject我们需要的响应即可
    return Promise.reject(err.response)
  },
)
// 定义请求方法
export function request(config: AxiosRequestConfigExtendType): Promise<AxiosResponse> {
  return instance.request(config)
}

export function withRequest<T = any>(rq: typeof request): ((
  config: AxiosRequestConfigExtendType
) => Promise<AjaxResult<T>>) {
  return config =>
    new Promise((resolve, reject) => {
      rq(config)
        .then(res => resolve(res.data))
        .catch(e => reject(e))
    })
}

/**
 * 获取数据
 * @param {string} url [请求路径]
 * @param {object} params [请求时携带的参数]
 * @param {object} headers [请求时携带的参数]
 * @returns {string} [json形式数据的字符串]
 */
export function get<T = any>(url: string, params?: object, headers?: RawAxiosRequestHeaders): Promise<AjaxResult<T>> {
  return new Promise((resolve, reject) => {
    instance({
      url,
      method: 'GET',
      params,
      headers,
    })
      .then(res => resolve(res.data))
      .catch(err => reject(err?.message))
  })
}

/**
 * 发送数据
 * @param {string} url [请求路径]
 * @param {object} data [发送的数据]
 * @returns {string} [json形式数据的字符串]
 */
export function post<T = any>(url: string, data?: object, headers?: RawAxiosRequestHeaders): Promise<AjaxResult<T>> {
  return new Promise((resolve, reject) => {
    instance({
      url,
      method: 'POST',
      data,
      headers,
    })
      .then(res => resolve(res.data))
      .catch(err => reject(err?.message))
  })
}
/**
 * 发送数据
 * @param {string} url [请求路径]
 * @param {object} data [发送的数据]
 * @returns {string} [json形式数据的字符串]
 */
export function put<T = any>(url: string, data?: object, headers?: RawAxiosRequestHeaders): Promise<AjaxResult<T>> {
  return new Promise((resolve, reject) => {
    instance({
      url,
      method: 'Put',
      data,
      headers,
    })
      .then(res => resolve(res.data))
      .catch(err => reject(err?.message))
  })
}
/**
 * 发送数据
 * @param {string} url [请求路径]
 * @param {object} data [发送的数据]
 * @returns {string} [json形式数据的字符串]
 */
export function del<T = any>(url: string, data?: object, headers?: RawAxiosRequestHeaders): Promise<AjaxResult<T>> {
  return new Promise((resolve, reject) => {
    instance({
      url,
      method: 'DELETE',
      data,
      headers,
    })
      .then(res => resolve(res.data))
      .catch(err => reject(err?.message))
  })
}

// 访问基址
export const BASE_URL = baseConfig.baseURL
/** 上传 */
export const UPLOAD_URL = import.meta.env.VITE_UPLOAD_URL
/** 上传请求头 */
// export const upload_headers = {
// }

// export const TOKEN = Cookies.get(UserInfoEnum.TOKEN);
export const TOKEN = localStorage.getItem(UserInfoEnum.TOKEN)
export default instance
